﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http.Headers;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using RESTAgent.Interfaces;
using RESTAgent.Tools;


namespace RESTAgent.Browser
{
	public partial class BrowserForm : Form
	{
		private readonly RestAgent RestAgent;
		private readonly string _RootUrl;
		private readonly Func<IHypermediaContent, string> _ContentFormatter;

    

		public BrowserForm(ISemanticsProvider semantics, Func<IHypermediaContent, string> contentFormatter, string rootUrl, string username = null, string password = null)
		{
			_RootUrl = rootUrl;
			_ContentFormatter = contentFormatter;

			InitializeComponent();

			RestAgent = new RestAgent {
				SynchronizationObject = this
			};

			if (username != null) {
				RestAgent.SetBasicCredentials(username, password);
			}
			
			RestAgent.RegisterDefaultResponseCompleteHandler(OnNavigate);
			RestAgent.RegisterDefaultErrorHandler(ex => {
				var msg = ex.Message;

				while (ex.InnerException != null) {
					ex = ex.InnerException;
					msg += "\n\n" + ex.Message;
				}

				statusResponseCode.Text = ex.Message;		// Innermost exception is probably most relevant

				MessageBox.Show(msg, "Error");

				txtLocation.Enabled = true;
				cmdUp.Enabled = GetUpLink(RestAgent.CurrentLocation).Target != null;
				cmdGo.Enabled = true;
				txtContent.Enabled = true;
			});

			RestAgent.RegisterSemanticsProvider(semantics);

			RestAgent.AutoSetAcceptedMediaTypes(true);


			Shown += (sender, e) => {
				InitialNavigate();
			};

			cmdGo.Click += (sender, e) => Navigate(txtLocation.Text);
			cmdUp.Click += (sender, e) => NavigateUp(RestAgent.CurrentLocation);
			
			lstLinks.DoubleClick += (sender, e) => {
				if (lstLinks.SelectedItems.Count == 0) {
					return;
				}

				var item = lstLinks.SelectedItems[0];
				Navigate(item.SubItems[1].Text);
			};
		}



		private void InitialNavigate()
		{
			txtLocation.Text = _RootUrl;
			Navigate(_RootUrl);
		}


		private void Navigate(string url)
		{;
			statusResponseCode.Text = "Navigating...";
			txtContent.Enabled = false;
			cmdUp.Enabled = cmdGo.Enabled = txtLocation.Enabled = false;

			RestAgent.NavigateTo(new Link(url));
		}


		private void NavigateUp(ILink fromLink)
		{
			Navigate(GetUpLink(fromLink).Target.OriginalString);
		}


		private ILink GetUpLink(ILink fromLink)
		{
			if (fromLink == null) {
				return new Link((Uri)null);
			}

			var target = fromLink.Target.IsAbsoluteUri ? fromLink.Target.AbsolutePath : fromLink.Target.OriginalString;
			if (!target.TrimEnd('/').Contains('/')) {
				return new Link((Uri)null);
			}

			target = target.Substring(0, target.TrimEnd('/').LastIndexOf('/') + 1);
			var url = Uri.IsWellFormedUriString(target, UriKind.RelativeOrAbsolute) ? new Uri(target, UriKind.RelativeOrAbsolute) : null;

			return new Link(url);
		}



		private void OnNavigate(IHypermediaContent content)
		{
			txtLocation.Text = RestAgent.CurrentLocation.Target.OriginalString;

			var status = ((int)RestAgent.CurrentStatusCode).ToString();
			if (content != null) {
				status += " | " + content.MediaType;
			}

			statusResponseCode.Text = status;
			txtLocation.Enabled = true;
			cmdUp.Enabled = GetUpLink(RestAgent.CurrentLocation).Target != null;
			cmdGo.Enabled = true;
			txtContent.Enabled = true;

			txtContent.Text = "";
			if (content != null) {
				txtContent.Text = _ContentFormatter(content);
			}
			

			lstLinks.Items.Clear();

			if (content == null) {
				return;
			}

			try {
				var headerLinks = content.GetHeaderLinks();

				foreach (var link in headerLinks) {
					var item = CreateLinkItem(link);
					item.Group = lstLinks.Groups[0];
					lstLinks.Items.Add(item);
				}

				foreach (var link in content.GetLinks().Except(headerLinks)) {
					var item = CreateLinkItem(link);
					item.Group = lstLinks.Groups[1];
					lstLinks.Items.Add(item);
				}
			}
			catch (LinkExtractorNotFoundException) {  }
		}


		private ListViewItem CreateLinkItem(ILink link)
		{
			return new ListViewItem(new[] {
				link.Relation,
				link.Target.IsAbsoluteUri ? link.Target.PathAndQuery : link.Target.OriginalString
			});
		}
	}
}
